home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Visual / VMake / reader.c < prev    next >
C/C++ Source or Header  |  1994-02-01  |  16KB  |  470 lines

  1. #include "vmake.h"
  2.  
  3. Prototype int get_simple_token(char *buf);
  4. Prototype int get_token(char *buf1, char *buf2, char *buf3);
  5. Prototype struct G_OBJECT **newobj(struct G_OBJECT **objlist, int class, char *buf);
  6. Prototype int parse_config(char *cfname);
  7. Prototype int init_config(char *cfname);
  8. Prototype void close_config(void);
  9.  
  10. #define MAX_STRTOK     128    /* The largest string we allow for a string token */
  11. /*********************************************************************
  12.  * TOKENS:
  13.  *      TOK_EOF     End of file
  14.  *                  '/''*' '*''/'
  15.  *      TOK_STRING  "string"
  16.  *      TOK_STRING  'string'
  17.  *      TOK_BAR     BAR
  18.  *      TOK_TEXT    TEXT   <string> <string>
  19.  *      TOK_CONFIG  CONFIG <string> <string>
  20.  *      TOK_SUBRTN  SUBRTN <string> <string>
  21.  *      TOK_BUTTON  BUTTON <string> <string>
  22.  *      TOK_CHECK   CHECK  <string> <string> <string>
  23.  *      TOK_CYCLE   CYCLE  <string>
  24.  *      TOK_ITEM    ITEM   <string> <string>
  25.  *      TOK_LIST    LIST   <string> <string> <string>
  26.  *      TOK_MENU    MENU   <string>
  27.  *      TOK_STRING  STRING <string> <string>
  28.  *      TOK_TITLE   TITLE  <string>
  29.  *      TOK_VALUE   VALUE  <string> <string>
  30.  */
  31. #define TOK_ERROR  -1
  32. #define TOK_EOF     0 /* Note ordering of ERROR/EOF is assumed for easy tests below */
  33. #define TOK_STRTOK  1
  34. #define TOK_TOKEN   2
  35. #define TOK_BAR     3
  36. #define TOK_BUTTON  4
  37. #define TOK_CHECK   5
  38. #define TOK_CYCLE   6
  39. #define TOK_ITEM    7
  40. #define TOK_LIST    8
  41. #define TOK_MENU    9
  42. #define TOK_STRING 10
  43. #define TOK_TITLE  11
  44. #define TOK_VALUE  12
  45. #define TOK_TEXT   13
  46. #define TOK_CONFIG 14
  47. #define TOK_SUBRTN 15
  48.  
  49. struct TOK_LOOK {
  50.    char toktype;   /* Value to return for this token                        */
  51.    char token[6];  /* Note that we only allow 6 characters in a token       */
  52.    char strings;   /* Number of strings that the token takes as an argument */
  53. };
  54.  
  55. struct TOK_LOOK tokens[] = {
  56.    { TOK_BAR,     "BAR   ", 0},
  57.    { TOK_BUTTON,  "BUTTON", 2},
  58.    { TOK_CHECK,   "CHECK ", 3},
  59.    { TOK_CYCLE,   "CYCLE ", 1},
  60.    { TOK_ITEM,    "ITEM  ", 3},
  61.    { TOK_LIST,    "LIST  ", 2},
  62.    { TOK_MENU,    "MENU  ", 1},
  63.    { TOK_STRING,  "STRING", 2},
  64.    { TOK_TITLE,   "TITLE ", 1},
  65.    { TOK_VALUE,   "VALUE ", 2},
  66.    { TOK_TEXT,    "TEXT  ", 2},
  67.    { TOK_CONFIG,  "CONFIG", 2},
  68.    { TOK_SUBRTN,  "SUBRTN", 2},
  69. };
  70. #define MAX_LOOK (sizeof(tokens)/sizeof(struct TOK_LOOK))
  71.  
  72. /*********************************************************************
  73.  * Character classes:
  74.  *  0  CL_EOF    - EOF
  75.  *  1  CL_SLASH  - /
  76.  *  2  CL_STAR   - *
  77.  *  3  CL_DQUOTE - "
  78.  *  4  CL_SQUOTE - '
  79.  *  5  CL_ALPHA  - A-Z a-z
  80.  *  6  CL_BLANK  - ' ' \t \n
  81.  *  7  CL_OTHER  - Anything else
  82.  */
  83. #define CL_EOF     0
  84. #define CL_SLASH   1
  85. #define CL_STAR    2
  86. #define CL_DQUOTE  3
  87. #define CL_SQUOTE  4
  88. #define CL_ALPHA   5
  89. #define CL_BLANK   6
  90. #define CL_OTHER   7
  91. #define MAX_CL     8
  92.  
  93. /*********************************************************************
  94.  * States:
  95.  *  0  ST_SCN - SCAN   - Scanning - Looking for any character - skipping white space
  96.  *  1  ST_GSL - GOTSL  - Found /  - Checking for a matching * to start a comment
  97.  *  2  ST_CMT - CMT    - Comment  - Looking for a * to close a comment
  98.  *  3  ST_GST - GOTST  - Found *  - Checking for a / to close a comment
  99.  *  4  ST_DQT - DQUOTE - String " - Looking for a matching "
  100.  *  5  ST_SQT - SQUOTE - String ' - Looking for a matching '
  101.  *  6  ST_TOK - TOKEN  - Token    - Gathering a keyword token
  102.  */
  103. #define ST_SCN  0
  104. #define ST_GSL  1
  105. #define ST_CMT  2
  106. #define ST_GST  3
  107. #define ST_DQT  4
  108. #define ST_SQT  5
  109. #define ST_TOK  6
  110. #define MAX_ST 7
  111. #define MASK_ST 7
  112.  
  113. /*********************************************************************
  114.  * State Table Transitions:
  115.  *
  116.  *            Character Class
  117.  *            0-EOF   1-/      2-*      3-"      4-'      5-A-Z      6-Blank  7-Other
  118.  *   State
  119.  *   0 SCAN    END    GOTSL   ERROR    DQUOTE   SQUOTE    >TOKEN     SCAN     ERROR
  120.  *   1 GOTSL  ERROR   ERROR   CMT      ERROR    ERROR     ERROR      ERROR    ERROR
  121.  *   2 CMT    ERROR   CMT     GOTST    CMT      CMT       CMT        CMT      CMT
  122.  *   3 GOTST  ERROR   SCAN    CMT      CMT      CMT       CMT        CMT      CMT
  123.  *   4 DQUOTE ERROR   >DQUOTE >DQUOTE  !SCAN    >DQUOTE   >DQUOTE    >DQUOTE  >DQUOTE
  124.  *   5 SQUOTE ERROR   >SQUOTE >SQUOTE  >SQUOTE  !SCAN     >SQUOTE    >SQUOTE  >SQUOTE
  125.  *   6 TOKEN  +END    +GOTSL  ERROR    +DQUOTE  +SQUOTE   >TOKEN     +SCAN    ERROR
  126.  * Note: >     - AC_SAV - Means to append the current character and continue scan
  127.  *       !     - AC_STR - Means to return the current token as a string.
  128.  *       +     - AC_TOK - Means to return the current token as a keyword
  129.  *       ERROR - AC_ERR - Indicates issuing an error
  130.  *       END   - AC_END - Indicates returing the END token.
  131.  */
  132. #define AC_SKP (0<<5) /* Must be zero - the default to do nothing */
  133. #define AC_SAV (1<<5)
  134. #define AC_STR (2<<5)
  135. #define AC_TOK (3<<5)
  136. #define AC_ERR (4<<5)
  137. #define AC_END (5<<5)
  138. #define MASK_AC (7<<5)
  139.  
  140. char statetab[MAX_ST][MAX_CL] =
  141. {
  142. /* 0 ST_SCN  */
  143.    { AC_END,        ST_GSL,         AC_ERR,         ST_DQT,
  144.      ST_SQT,        AC_SAV|ST_TOK,  ST_SCN,         AC_ERR         },
  145. /* 1 ST_GSL */
  146.    { AC_ERR,        AC_ERR,         ST_CMT,         AC_ERR,
  147.      AC_ERR,        AC_ERR,         AC_ERR,         AC_ERR         },
  148. /* 2 ST_CMT   */
  149.    { AC_ERR,        ST_CMT,         ST_GST,         ST_CMT,
  150.      ST_CMT,        ST_CMT,         ST_CMT,         ST_CMT         },
  151. /* 3 ST_GST */
  152.    { AC_ERR,        ST_SCN,         ST_CMT,         ST_CMT,
  153.      ST_CMT,        ST_CMT,         ST_CMT,         ST_CMT         },
  154. /* 4 ST_DQT*/
  155.    { AC_ERR,        AC_SAV|ST_DQT,  AC_SAV|ST_DQT,  AC_STR|ST_SCN,
  156.      AC_SAV|ST_DQT, AC_SAV|ST_DQT,  AC_SAV|ST_DQT,  AC_SAV|ST_DQT  },
  157. /* 5 ST_SQT*/
  158.    { AC_ERR,        AC_SAV|ST_SQT,  AC_SAV|ST_SQT,  AC_SAV|ST_SQT,
  159.      AC_STR|ST_SCN, AC_SAV|ST_SQT,  AC_SAV|ST_SQT,  AC_SAV|ST_SQT  },
  160. /* 6 ST_TOK */
  161.    { AC_TOK|ST_SCN, AC_TOK|ST_GSL,  AC_ERR,         AC_TOK|ST_DQT,
  162.      AC_TOK|ST_SQT, AC_SAV|ST_TOK,  AC_TOK|ST_SCN,  AC_ERR         },
  163. };
  164.  
  165. /*
  166.  * Get a simple token from the file.
  167.  * No parsing of semantics is done at this level.
  168.  */
  169. int get_simple_token(char *buf)
  170. {
  171.    int c;
  172.    int pos;
  173.    int class;
  174.    int action;
  175.  
  176.    pos = 0;
  177.  
  178.    for(;;)
  179.    {
  180.       /* Get the next character from the input file and assign a character class */
  181.       c = getc(global.fp);
  182.       class = CL_OTHER;
  183.       switch(c)
  184.       {
  185.          case EOF:  class = CL_EOF;    break;
  186.          case '/':  class = CL_SLASH;  break;
  187.          case '*':  class = CL_STAR;   break;
  188.          case '"':  class = CL_DQUOTE; break;
  189.          case '\'': class = CL_SQUOTE; break;
  190.          case '\n': global.line++;
  191.          case ' ':
  192.          case '\t':  class = CL_BLANK;  break;
  193.          default:
  194.             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
  195.                class = CL_ALPHA;
  196.             break;
  197.       }
  198.       /* Run us through the state table to get an action and a new state */
  199.       action = statetab[global.state][class];
  200.       global.state = (action & MASK_ST);
  201.  
  202.       /* Perform the work for the action */
  203.       switch(action & MASK_AC)
  204.       {
  205.          case AC_SAV: if (pos < MAX_STRTOK) /* make sure we don't overflow the buffer */
  206.                       {
  207.                          buf[pos++] = c;  /* Save the character */
  208.                          break;
  209.                       }
  210.                       /* Else fall through to the error case */
  211.          case AC_ERR: return(TOK_ERROR);
  212.          case AC_STR: buf[pos] = 0;   /* Null terminate what we gathered */
  213.                       return(TOK_STRTOK);
  214.          case AC_TOK: buf[pos] = 0;
  215.                       return(TOK_TOKEN);
  216.          case AC_END: return(TOK_EOF);
  217.       }
  218.    }
  219. }
  220.  
  221. /*
  222.  * Get the next token and any associated strings.
  223.  */
  224. int get_token(char *buf1,
  225.               char *buf2,
  226.               char *buf3
  227.              )
  228. {
  229.    int i;
  230.    int j;
  231.    int toktype;
  232.    int len;
  233.    char *strs[3];
  234.  
  235.    strs[0] = buf1;
  236.    strs[1] = buf2;
  237.    strs[2] = buf3;
  238.  
  239.    toktype = get_simple_token(buf1);
  240.    if (toktype == TOK_EOF)   return(toktype);
  241.    if (toktype != TOK_TOKEN) return(TOK_ERROR);
  242.  
  243.    /* Go through and uppercase the string */
  244.    /* we KNOW that it consists of only upper/lower case letters */
  245.    len = strlen(buf1);
  246.    if (len > 6) return(TOK_ERROR);
  247.    strcpy(buf1+len, "     "); /* Make sure we blank pad for the memcmp */
  248.    for(i = 0; i < 6; i++)
  249.       if (buf1[i] >= 'a') buf1[i] -= ('a'-'A');
  250.  
  251.    /* Now go through the table and look for a token */
  252.    for (i = 0; i < MAX_LOOK; i++)
  253.       if (!memcmp(buf1, tokens[i].token, 6)) break;
  254.    if (i == MAX_LOOK) return(TOK_ERROR);
  255.  
  256.    /* We have a matching token, get any strings that it wants */
  257.    for(j = 0; j < tokens[i].strings; j++)
  258.    {
  259.       toktype = get_simple_token(strs[j]);
  260.       if (toktype != TOK_STRTOK) return(TOK_ERROR);
  261.    }
  262.  
  263.    /* Everything checks out, let them know what type of token they got */
  264.    return((int)tokens[i].toktype);
  265. }
  266.  
  267. void init_group(struct G_OBJECT *object)
  268. {
  269.    while(object != NULL)
  270.    {
  271.       if (object->next) object->next->prev = object;
  272.       if (object->class == CLASS_CYCLE)
  273.       {
  274.          struct G_VALUE *val;
  275.          struct G_CYCLE *cyc;
  276.  
  277.          cyc = (struct G_CYCLE *)object;
  278.  
  279.          cyc->curval = cyc->values;
  280.          for(val = cyc->curval; val; val = val->next)
  281.          {
  282.             if (cyc->base.next) cyc->base.next->prev = (struct G_OBJECT *)cyc;
  283.          }
  284.       }
  285.       object = object->next;
  286.    }
  287. }
  288. /*
  289.  * Allocate an object structure to hold an entry
  290.  */
  291. static short sizetab[] = { 0,
  292.                           sizeof(struct G_STRING),
  293.                           sizeof(struct G_CYCLE),
  294.                           sizeof(struct G_CHECK),
  295.                           sizeof(struct G_LIST),
  296.                           sizeof(struct G_BUTTON)
  297.                          };
  298.  
  299. struct G_OBJECT **newobj(struct G_OBJECT **objlist,
  300.                          int class,
  301.                          char *buf
  302.                         )
  303. {
  304.    struct G_OBJECT *obj;
  305.    obj = get_mem(sizetab[class]);
  306.    if (obj == NULL) return(NULL);
  307.  
  308.    if (objlist) *objlist = obj;
  309.    obj->class = class;
  310.    obj->title = savestr(buf);
  311.    return(&obj->next);
  312. }
  313.  
  314. /*
  315.  * Parse the configuration file (name is cfname)
  316.  * return:  0 if OK
  317.  *          1 if syntax error in config file
  318.  *          2 if unable to open config file
  319.  */
  320. int parse_config(char *cfname)
  321. {
  322.    static char buf1[MAX_STRTOK+2], buf2[MAX_STRTOK+2], buf3[MAX_STRTOK+2];
  323.    int toktype;
  324.    int menupos;
  325.    int buttonpos;
  326.    int strpos;
  327.    struct G_OBJECT **objlist;
  328.    struct G_VALUE  **valent;
  329.  
  330.    objlist = &global.objects;
  331.    valent = NULL;
  332.  
  333.    menupos = buttonpos = 0;
  334.    if (init_config(cfname)) return(2);
  335.  
  336.    while((toktype = get_token(buf1, buf2, buf3)) > TOK_EOF)
  337.    {
  338.       switch(toktype)
  339.       {
  340.          case TOK_TEXT:   strpos = atoi(buf1) - 1;
  341.                           if ((strpos < 0) || (strpos >= NUM_TEXT)) goto error;
  342.                           global.text[strpos] = savestr(buf2);
  343.                           break;
  344.          case TOK_CONFIG: strpos = atoi(buf1) - 1;
  345.                           if ((strpos < 0) || (strpos >= NUM_CONFIG)) goto error;
  346.                           global.text[CONFIG_BASE+strpos] = savestr(buf2);
  347.                           break;
  348.          case TOK_SUBRTN: strpos = atoi(buf1) - 1;
  349.                           if ((strpos < 0) || (strpos >= NUM_SUBRTN)) goto error;
  350.                           global.text[SUBRTN_BASE+strpos] = savestr(buf2);
  351.                           break;
  352.          case TOK_BAR:    global.menuitem[menupos].nm_Type   = MENU_ITEM;
  353.                           global.menuitem[menupos].nm_Label  = NM_BARLABEL;
  354.                           if (menupos >= MAX_MENU) goto error;
  355.                           menupos++;
  356.                           break;
  357.          case TOK_MENU:   global.menuitem[menupos].nm_Type   = MENU_MENU;
  358.                           global.menuitem[menupos].nm_Label  = savestr(buf1);
  359.                           if (menupos >= MAX_MENU) goto error;
  360.                           menupos++;
  361.                           break;
  362.          case TOK_ITEM:   global.menuitem[menupos].nm_Type   = MENU_ITEM;
  363.                           global.menuitem[menupos].nm_Label  = savestr(buf1);
  364.                           if (buf2[0])
  365.                              global.menuitem[menupos].nm_CommKey = savestr(buf2);
  366.                           global.menuitem[menupos].nm_UserData = savestr(buf3);
  367.                           if (menupos >= MAX_MENU) goto error;
  368.                           menupos++;
  369.                           break;
  370.          case TOK_BUTTON: if (buttonpos >= MAX_BUTTON) goto error;
  371.                           global.button[buttonpos].base.title = savestr(buf1);
  372.                           global.button[buttonpos++].command    = savestr(buf2);
  373.                           break;
  374.          case TOK_TITLE:  buf1[MAX_TITLE-1] = 0;
  375.                           strcpy(global.title2, buf1);
  376.                           break;
  377.          case TOK_STRING: objlist = newobj(objlist, CLASS_STRING, buf1);
  378.                           if (!objlist) goto error;
  379.                           ((struct G_STRING *)objlist)->option = savestr(buf2);
  380.                           valent = NULL;
  381.                           break;
  382.          case TOK_CHECK:  objlist = newobj(objlist, CLASS_CHECK, buf1);
  383.                           if (!objlist) goto error;
  384.                           ((struct G_CHECK *)objlist)->option0 = savestr(buf2);
  385.                           ((struct G_CHECK *)objlist)->option1 = savestr(buf3);
  386.                           valent = NULL;
  387.                           break;
  388.          case TOK_LIST:   objlist = newobj(objlist, CLASS_LIST, buf1);
  389.                           if (!objlist) goto error;
  390.                           ((struct G_LIST *)objlist)->option = savestr(buf2);
  391.                           if (!stricmp(buf2, "Files"))
  392.                              global.filelist = (struct G_LIST *)objlist;
  393.                           valent = NULL;
  394.                           break;
  395.          case TOK_CYCLE:  objlist = newobj(objlist, CLASS_CYCLE, buf1);
  396.                           if (!objlist) goto error;
  397.                           valent = &((struct G_CYCLE *)objlist)->values;
  398.                           break;
  399.          case TOK_VALUE:  if (valent == NULL) goto error;
  400.                           *valent = get_mem(sizeof(struct G_VALUE));
  401.                           if (!*valent) goto error;
  402.                           (*valent)->next = NULL;
  403.                           (*valent)->title = savestr(buf1);
  404.                           (*valent)->option = savestr(buf2);
  405.                           (*valent)->string = NULL;
  406.                           if (strchr(buf2, '%'))
  407.                           {
  408.                              struct G_STRING *gstr;
  409.  
  410.                              gstr = get_mem(sizeof(struct G_STRING));
  411.                              if (!gstr) goto error;
  412.                              gstr->base.class = CLASS_STRING;
  413.                              (*valent)->string = gstr;
  414.                           }
  415.                           valent = &((*valent)->next);
  416.                           break;
  417.       }
  418.    }
  419.    global.menuitem[menupos].nm_Type = MENU_END;
  420.  
  421.    if (toktype == TOK_ERROR)
  422.    {
  423. error:
  424.       sprintf(global.title, "ERROR- %s line %d", cfname, global.line);
  425.       global.objects = NULL; /* memory will get cleaned up on exit */
  426.       /* global.menuitem gets cleared in vmake.c to handle case of */
  427.       /* failure to open config file as well.                      */
  428.       return(1);
  429.    }
  430.    close_config();
  431.  
  432.    /* Now we need to go through the groups and sanitize the pointers as well */
  433.    /* as initialize all the default states                                   */
  434.    init_group(global.objects);
  435.    return(0);
  436. }
  437.  
  438. /*
  439.  * Open the configuration file and initialize any global data
  440.  */
  441. int init_config(char *cfname)
  442. {
  443.    struct Process *mytask;
  444.    APTR saveptr;
  445.  
  446.    global.state = ST_SCN;
  447.    global.line  = 1;
  448.    mytask = (struct Process *)FindTask(NULL);
  449.    saveptr = mytask->pr_WindowPtr;
  450.    mytask->pr_WindowPtr = (APTR)-1;
  451.    global.fp = fopen(cfname, "r");
  452.    mytask->pr_WindowPtr = saveptr;
  453.    if (global.fp == NULL)
  454.    {
  455.       sprintf(global.title, "ERROR- No %s", cfname);
  456.       return(1);
  457.    }
  458.    return(0);
  459. }
  460.  
  461. /*
  462.  * Close the configuration file and clean up anything else necessary
  463.  */
  464. void close_config()
  465. {
  466.    if (global.fp)
  467.       fclose(global.fp);
  468.    global.fp = NULL;
  469. }
  470.